package battlecruiser.shooter;

import battlecruiser.board.ObserverBoard;
import battlecruiser.board.cell.coordinate.Coordinate;
import battlecruiser.ship.placement.ship.Ship;
import battlecruiser.shooter.reader.RandomTargetReader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Yakiv Tymoshenko
 * @since 03.10.12
 */
public class ComputerShooter extends Shooter {

    private DamageReport previousDamageReport;
    private List<Coordinate> damagedDecks;


    public ComputerShooter(ObserverBoard observerBoard) {
        this.previousDamageReport = null;
        this.damagedDecks = new ArrayList<Coordinate>();
        this.observerBoard = observerBoard;
        this.targetReader = new RandomTargetReader(observerBoard);
    }

    @Override
    public DamageReport shoot() throws IOException {
        return shoot(nextTarget(previousDamageReport));

    }

    @Override
    public DamageReport shoot(Coordinate target) throws IOException {
        DamageReport result = super.shoot(target);

        decideNextMove(result);
        if ((result != null) && (result.getShotResult() == ShotResult.HIT)) {
            result = shoot(nextTarget(result));
        }

        return result;
    }

    private void decideNextMove(DamageReport damageReport) {
        if (damageReport != null) {
            if (damageReport.getShotResult() == ShotResult.HIT) {
                if (isDestroyed(damageReport.getShipUnderAttack())) {
                    previousDamageReport = null;
                    damagedDecks.clear();
                } else {
                    previousDamageReport = damageReport;
                    damagedDecks.add(damageReport.getTarget());
                }
            } else {
                if (damagedDecks.size() > 0) {
                    previousDamageReport = damageReport;
                }
            }
        }
    }

    private Coordinate nextTarget(DamageReport damageReport) throws IOException {
        Coordinate result;
        if ((damageReport == null) ||
                ((damageReport.getShipUnderAttack() != null) && (isDestroyed(damageReport.getShipUnderAttack())))) {
            result = targetReader.readTarget();
        } else {
            if (damagedDecks.size() > 1) {
                result = targetReader.selectRandomNeighbourOnTheSameLine(damagedDecks);
            } else {
                result = targetReader.selectRandomNeighbour(damagedDecks.get(0));
            }
        }
        return result;
    }

    private boolean isDestroyed(Ship ship) {
        return observerBoard.isDestroyed(ship);
    }
}
